/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.madpie.converters;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
import org.madpie.schemas.DiskType;
import org.madpie.schemas.Disks;
import org.madpie.schemas.PartitionType;
import org.xml.sax.SAXException;

/**
 *
 * @author Niklas Rehfeld
 */
public class Fdisk
{

    private Schema diskSchema;
    private Disks disks;
    private JAXBContext jbc;

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) throws FileNotFoundException, IOException, JAXBException
    {
        Logger.getLogger(Fdisk.class.getName()).setLevel(Level.ALL);
        if (args.length < 2)
        {
            printUsage();
            System.exit(-1);
        }

        InputStream is;
        OutputStream os;
        File inFile = new File(args[0]);

        if (args[0].equals("-"))
        {
            is = System.in;
        }
        else
        {
            if (!inFile.canRead())
            {
                Logger.getLogger(Fdisk.class.getName()).log(Level.WARNING,
                        "Can't read input file '{0}'", inFile.getPath());
                System.exit(-1);
            }
            is = new FileInputStream(inFile);
        }
        if (args[1].equals("-"))
        {
            os = System.out;
        }
        else
        {
            File outFile = new File(args[1]);
            outFile.createNewFile();
            os = new FileOutputStream(outFile);
        }

        Fdisk f = new Fdisk(is, os);
        f.parseInput(is);
        f.writeOut(os);
    }

    public Fdisk(InputStream is, OutputStream os)
    {
        try
        {
            jbc = JAXBContext.newInstance(Disks.class);
        } catch (JAXBException ex)
        {
            Logger.getLogger(Fdisk.class.getName()).log(Level.SEVERE,
                    "Couldn't create JAXBContext.", ex);
        }
        disks = new Disks();
        try
        {
            diskSchema = SchemaFactory.newInstance(
                    XMLConstants.W3C_XML_SCHEMA_NS_URI).newSchema(new File(
                    "./source/xml/disks.xsd"));
        } catch (SAXException ex)
        {
            Logger.getLogger(Fdisk.class.getName()).log(Level.WARNING,
                    "Couldn't find schema for validation, \n XML will not be validated.");
        }

    }

    public void parseInput(InputStream is)
    {
        Scanner s = new Scanner(is);
        String line;
        DiskType currentDisk = null;
        while (s.hasNextLine())
        {
            line = s.nextLine();
            if (line.startsWith("Disk /dev/"))
            {
                String[] parts = line.split("\\s+");
                if (parts.length != 6)
                {
                    Logger.getLogger(Fdisk.class.getName()).log(Level.WARNING,
                            "unexpected number of parts to Disk line...");
                    continue;
                }
                currentDisk = new DiskType();
                currentDisk.setSize(Long.parseLong(parts[4].trim()));
                currentDisk.setPath(parts[1].replaceAll(":", "").trim());
                disks.getDisk().add(currentDisk);
            }
            else if (line.startsWith("/dev/")) //partitions
            {
                PartitionType p = new PartitionType();
                String[] parts = line.split("\\s+");
                if (parts.length == 7) //bootable flag not empty
                {
                    p.setName(parts[0].trim());
                    p.setBootable(true);
                    //length given in 1k blocks (usually i think...)
                    String l = parts[4].trim();
                    if (l.endsWith("+"))
                    {
                        l = l.replace('+', ' ').trim();
                    }
                    
                    p.setSize(Long.parseLong(l) * 1024L);
                    p.setType(parts[6].trim());
                }
                else if (parts.length == 6)
                {
                    p.setName(parts[0].trim());
                    p.setBootable(false);
                    String l = parts[3].trim();
                    if (l.endsWith("+"))
                    {
                        l = l.replace('+', ' ').trim();
                    }
                    p.setSize(Long.parseLong(l) * 1024L);
                    p.setType(parts[5].trim());
                }
                else
                {
                    Logger.getLogger(Fdisk.class.getName()).log(Level.WARNING,
                            "Partition info wrong length: " + parts.length);
                    continue;
                }
                currentDisk.getPartition().add(p);
            }
        }
    }

    public void writeOut(OutputStream os) throws JAXBException
    {
        JAXBContext jbc = JAXBContext.newInstance(Disks.class);
        Marshaller m = jbc.createMarshaller();
        m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        if (diskSchema != null)
        {
            m.setSchema(diskSchema);
        }
        m.marshal(disks, os);
    }

    private static void printUsage()
    {
        System.out.println("Usage: fdisk2xml input output");
    }
}
